package com.nowcoder.community.service.impl;

import com.nowcoder.community.entity.User;
import com.nowcoder.community.service.FollowService;
import com.nowcoder.community.service.UserService;
import com.nowcoder.community.constant.CommunityConstant;
import com.nowcoder.community.util.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author 花木凋零成兰
 * @date 2024/3/18 15:46
 */
@Service
public class FollowServiceImpl implements FollowService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private UserService userService;

    /**
     * 关注某个实体
     * @param userId
     * @param entityType
     * @param entityId
     */
    @Override
    public void follow(int userId, int entityType, int entityId) {
        // 事务
        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);   // 关注某实体的key
                String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId); // 获取某实体粉丝的key

                operations.multi(); // 启用事务

                // 某用户关注实体
                operations.opsForZSet().add(followeeKey, entityId, System.currentTimeMillis());
                // 某实体的粉丝 即被关注
                operations.opsForZSet().add(followerKey, userId, System.currentTimeMillis());

                return operations.exec();   // 结束事务 并提交事务
            }
        });
    }

    /**
     * 取消某个实体
     * @param userId
     * @param entityType
     * @param entityId
     */
    @Override
    public void unfollow(int userId, int entityType, int entityId) {
        // 事务
        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);   // 关注某实体的key
                String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId); // 获取某实体粉丝的key

                operations.multi(); // 启用事务

                // 某用户取消关注某实体
                operations.opsForZSet().remove(followeeKey, entityId);
                // 某实体的粉丝减少 即被取消关注
                operations.opsForZSet().remove(followerKey, userId);

                return operations.exec();   // 结束事务 并提交事务
            }
        });
    }

    /**
     * 查询关注该实体的数量
     *
     * @param userId
     * @param entityType
     * @return
     */
    @Override
    public long findFolloweeCount(int userId, int entityType) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().zCard(followeeKey);
    }

    /**
     * 查询某实体 粉丝的数量
     * @param entityType
     * @param entityId
     * @return
     */
    @Override
    public long findFollowerCount(int entityType, int entityId) {
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        return redisTemplate.opsForZSet().zCard(followerKey);
    }

    /**
     * 查询当前用户是否关注了某实体
     * @param userId
     * @param entityType
     * @param entityId
     * @return
     */
    @Override
    public boolean hasFollowed(int userId, int entityType, int entityId) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().score(followeeKey, entityId) != null;
    }

    /**
     * 查询某用户关注的人 列表
     * @param userId
     * @param offset
     * @param limit
     * @return
     */
    @Override
    public List<Map<String, Object>> findFollows(int userId, int offset, int limit) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, CommunityConstant.ENTITY_TYPE_USER);
        Set<Object> objects = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);
        if (objects == null) return null;
        Set<Integer> targetIds = new LinkedHashSet<>();
        for (Object object : objects) {
            targetIds.add((Integer) object);
        }

        List<Map<String, Object>> list = new ArrayList<>();
        for (Integer targetId : targetIds) {
            Map<String, Object> map = new HashMap<>();
            // 获取关注的用户
            User user = userService.findUserById(targetId);
            map.put("user", user);
            // 获取关注某用户时 时间
            Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
            map.put("followTime", new Date(score.longValue()));

            list.add(map);

        }

        return list;
    }

    /**
     * 查询某用户的粉丝
     * @param userId
     * @param offset
     * @param limit
     * @return
     */
    @Override
    public List<Map<String, Object>> findFollowers(int userId, int offset, int limit) {
        String followerKey = RedisKeyUtil.getFollowerKey(CommunityConstant.ENTITY_TYPE_USER, userId);
        Set<Object> objects = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);
        if (objects == null) return null;
        Set<Integer> targetIds = new LinkedHashSet<>();
        for (Object object : objects) {
            targetIds.add((Integer) object);
        }

        List<Map<String, Object>> list = new ArrayList<>();
        for (Integer targetId : targetIds) {
            Map<String, Object> map = new HashMap<>();
            // 获取关注的用户
            User user = userService.findUserById(targetId);
            map.put("user", user);
            // 获取关注某用户时 时间
            Double score = redisTemplate.opsForZSet().score(followerKey, targetId);
            map.put("followTime", new Date(score.longValue()));

            list.add(map);

        }
        return list;
    }

}
